﻿using System;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
#if NET40
using Microsoft.Practices.ServiceLocation;
#else
using CommonServiceLocator;
#endif


namespace Mvvm.Common.WindowExtensions
{
    /// <summary>
    /// 打开子窗口
    /// </summary>
    /// <param name="targetName"></param>
    /// <param name="viewModel"></param>
    /// <param name="parentWindow"></param>
    public delegate void OpenWindowRequestInParent(string targetName,IViewModel viewModel , Window parentWindow);
    public static class WindowExtensions
    {
        /// <summary>
        /// 创建窗口
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="model"></param>
        /// <returns></returns>
        public static T CreateWindow<T>(this IViewModel model) where T : Window
        {
            T t = Activator.CreateInstance<T>();
            t.DataContext = model;
            t.RegisterContext(model);
            return t;
        }

        /// <summary>
        /// 注册窗口拖动
        /// </summary>
        /// <param name="t"></param>
        /// <param name="uiElementName"></param>
        /// <param name="isSupportDoubleClick">是否支持双击操作</param>
        /// <returns></returns>
        [Obsolete("弃用，建议使用RegisterTitle方法")]
        public static T RegisterDrag<T>(this T t, string uiElementName = "BrTitle",bool isSupportDoubleClick=false) where T : Window
        {
            t.Loaded += (sender, args) =>
            {
                var br = t.FindVisualChildByName<UIElement>(uiElementName);
                if (br == null) return;
                br.MouseLeftButtonDown += (s, e) =>
                {
                    if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
                    {
                        t.DragMove();
                    }
                 
                };
            };
            return t;
        }

        /// <summary>
        /// 注册title
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="titleName"></param>
        /// <param name="isAllowDrag"></param>
        /// <param name="isAllowDoubleClick"></param>
        /// <returns></returns>
        public static T RegisterTitle<T>(this T t, string titleName = "BrTitle", bool isAllowDrag = true,
            bool isAllowDoubleClick = false) where T : Window
        {
            if (isAllowDrag is false && isAllowDoubleClick is false) return t;
            t.Loaded += (sender, args) =>
            {
                var br = t.FindVisualChildByName<UIElement>(titleName);
                if (br == null) return;
                br.MouseLeftButtonDown += (s, e) =>
                {
                    if (isAllowDrag)
                    {
                        if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
                        {
                            t.DragMove();
                        }
                    }

                    if (isAllowDoubleClick)
                    {
                        if (e.ClickCount < 2) return;
                        t.WindowState = t.WindowState == WindowState.Maximized
                            ? WindowState.Normal
                            : WindowState.Maximized;
                    }

                };
            };
            return t;
        }

        /// <summary>
        /// 注册最小按钮
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="minButtonName"></param>
        /// <returns></returns>
        public static T RegisterMinButton<T>(this T t, string minButtonName = "BtnMin") where T : Window
        {
            t.Loaded += (sender, args) =>
            {
                var btn = t.FindVisualChildByName<Button>(minButtonName);
                if (btn == null) return;
                btn.Click += (s, e) => { t.WindowState = WindowState.Minimized; };
            };
            return t;
        }
        /// <summary>
        /// 注册最大化按钮
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="minButtonName"></param>
        /// <returns></returns>
        public static T RegisterMaxButton<T>(this T t, string minButtonName = "BtnMax") where T : Window
        {
            t.Loaded += (sender, args) =>
            {
                var btn = t.FindVisualChildByName<Button>(minButtonName);
                if (btn == null) return;
                btn.Click += (s, e) =>
                {
                    if (t.WindowState == WindowState.Maximized)
                    {
                        t.WindowState = WindowState.Normal;
                    }
                    else
                    {
                        t.WindowState = WindowState.Maximized;
                    }
                };
            };
            return t;
        }
        /// <summary>
        /// 注册关闭按钮
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="closeButtonName"></param>
        /// <returns></returns>
        public static T RegisterCloseButton<T>(this T t, string closeButtonName = "BtnClose") where T : Window
        {
            t.Loaded += (sender, args) =>
            {
                var btn = t.FindVisualChildByName<Button>(closeButtonName);
                if (btn == null) return;
                btn.Click += (s, e) => { t.Close(); };
            };
            return t;
        }

        /// <summary>
        /// 注册
        /// </summary>
        /// <param name="window"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public static Window RegisterContext<T>(this Window window,T context) where T:IViewModel
        {
            if (window == null) return null;
            if (context == null) return window;
            if (context is IModelLoaded loadedModel)
            {
                window.Loaded += (sender, args) => loadedModel.Loaded();
            }

            if (context is IModelClosing closingModel)
            {
                window.Closing += (sender, args) => closingModel.Closing();
            }

            if (context is IModelCloseCompleted closeModel)
            {
                window.Closed += (sender, args) => closeModel.CloseCompleted();
            }

            if (context is IModelClose closeNoticeWindow)
            {
                if (closeNoticeWindow.CloseModel != null)
                {
                    closeNoticeWindow.CloseModel.WindowClosed += window.Close;
                }
            }

            if (context is IModelDialog modelDialog)
            {
                if (modelDialog.DialogModel != null)
                {
                    modelDialog.DialogModel.ShowDialoged += window.ShowDialog;
                }
            }

            if (context is IModelDialogResult modelDialogResult)
            {
                if (modelDialogResult.DialogResultModel != null)
                {
                    modelDialogResult.DialogResultModel.ShowDialogedResult += window.ShowDialogResult;
                }
            }
            return window;
        }
        /// <summary>
        /// 注册打开子窗口
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="openRequest"></param>
        /// <returns></returns>
        public static T RegisterOpenChildWindow<T>(this T t,OpenWindowRequest openRequest) where T:IOpenWindow
        {
            t.OpenWindow = openRequest;
            return t;
        }
        /// <summary>
        /// 注册打开子窗口
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        public static T RegisterOpenChildWindow<T>(this T t, OpenWindowRequestInParent request) where T : Window
        {
            if (t.DataContext is IOpenWindow openWindow)
            {
                openWindow.OpenWindow = (name, model) => { request(name, model, t); };
            }

            return t;
        }
        /// <summary>
        /// 显示message消息
        /// </summary>
        /// <param name="window"></param>
        /// <param name="message"></param>
        /// <param name="caption"></param>
        /// <param name="okButtonStr"></param>
        /// <returns></returns>
        private static bool ShowDialog(this Window window,string message, string caption, string okButtonStr)
        {
            if (window.CheckAccess())
            {
                IShowDialog showDialog;
                try
                {
                    showDialog = ServiceLocator.Current.GetInstance<IShowDialog>();
                }
                catch (Exception ex)
                {
                    //LogHelper.Error("没有查找到显示message消息提示接口，使用默认的提示显示",ex);
                    showDialog=new DefaultShowDialog();
                }

                return showDialog.ShowDialog(window, message, caption, okButtonStr);
            }
            else
            {
#if NET40
                return (bool)window.Dispatcher.Invoke(new Func<bool>(() => ShowDialog(window, message, caption, okButtonStr)), DispatcherPriority.Normal);           
#else
                return window.Dispatcher.Invoke(() => ShowDialog(window, message, caption, okButtonStr), DispatcherPriority.Normal);
#endif



            }
        }

        /// <summary>
        /// 显示message消息
        /// </summary>
        /// <param name="window"></param>
        /// <param name="message"></param>
        /// <param name="caption"></param>
        /// <param name="okButtonStr"></param>
        /// <param name="cancelButtonStr"></param>
        /// <returns></returns>
        private static bool? ShowDialogResult(this Window window, string message, string caption, string okButtonStr,
            string cancelButtonStr)
        {
            if (window.CheckAccess())
            {
                IShowDialog showDialog;
                try
                {
                    showDialog = ServiceLocator.Current.GetInstance<IShowDialog>();
                }
                catch (Exception ex)
                {
                    //LogHelper.Error("没有查找到显示message消息提示接口，使用默认的提示显示",ex);
                    showDialog = new DefaultShowDialog();
                }

                return showDialog.ShowDialogResult(window, message, caption, okButtonStr, cancelButtonStr);
            }
            else
            {

#if NET40
                return (bool?)window.Dispatcher.Invoke(new Func<bool?>(() => ShowDialogResult(window, message, caption, okButtonStr, cancelButtonStr)),DispatcherPriority.Normal);
#else
                return window.Dispatcher.Invoke(
                    () => ShowDialogResult(window, message, caption, okButtonStr, cancelButtonStr),
                    DispatcherPriority.Normal);
#endif

            }
        }

        /// <summary>
        /// 根据名称查找控件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sourde"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static T FindName<T>(this FrameworkElement sourde, string name) where T : DependencyObject
        {
            var control = sourde.FindName(name) as T;
            return control;
        }
        /// <summary>
        /// 获取是否是设计模式
        /// </summary>
        /// <param name="control"></param>
        /// <returns></returns>
        public static bool GetIsInDesignMode(this DependencyObject control)
        {
            return System.ComponentModel.DesignerProperties.GetIsInDesignMode(control);
        }
        /// <summary>
        /// 获取父控件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static T FindVisualParent<T>(this DependencyObject source) where T : DependencyObject
        {
            while (source != null && source.GetType() != typeof(T))
                source = System.Windows.Media.VisualTreeHelper.GetParent(source);
            return source as T;
        }
        /// <summary>
        /// 查找子控件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <returns></returns>
        public static T FindVisualChild<T>(this DependencyObject parent) where T : DependencyObject
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
            {
                var child = VisualTreeHelper.GetChild(parent, i);
                if (child.GetType() == typeof(T))
                {
                    return child as T;
                }
                T result = FindVisualChild<T>(child);
                if (result != null)
                    return result;
            }

            return null;
        }

        /// <summary>
        /// 通过名称查找之控件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static T FindVisualChildByName<T>(this DependencyObject parent, string name) where T : DependencyObject
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
            {
                var child = VisualTreeHelper.GetChild(parent, i);
                //if (child.GetType() == typeof(T)) 这句不准确
                if (child is T t)
                {
                    string controlName = t.GetValue(Control.NameProperty) as string;
                    if (controlName == name)
                    {
                        return child as T;
                    }
                }

                T result = FindVisualChildByName<T>(child, name);
                if (result != null)
                    return result;
            }
            return null;
        }
    }
}
